package com.zhongen.wflow.workflow.config.listener;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zhongen.wflow.bean.entity.WflowModelHistorys;
import com.zhongen.wflow.mapper.WflowModelHistorysMapper;
import com.zhongen.wflow.workflow.bean.dto.NotifyDto;
import com.zhongen.wflow.workflow.bean.process.OrgUser;
import com.zhongen.wflow.workflow.bean.process.props.ApprovalProps;
import com.zhongen.wflow.workflow.bean.vo.ProcessHandlerParamsVo;
import com.zhongen.wflow.workflow.config.WflowGlobalVarDef;
import com.zhongen.wflow.workflow.service.NotifyService;
import com.zhongen.wflow.workflow.service.UserDeptOrLeaderService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.engine.runtime.ChangeActivityStateBuilder;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.service.delegate.DelegateTask;
import org.flowable.task.service.delegate.TaskListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author : willian fu
 * @date : 2022/8/23
 */
@Slf4j
@Component("userTaskListener")
public class UserTaskListener implements TaskListener, ExecutionListener {

	@Autowired
	private TaskService taskService;

	@Autowired
	private UserDeptOrLeaderService userService;

	@Autowired
	private RuntimeService runtimeService;

	@Autowired
	private NotifyService notifyService;

	@Autowired
	private WflowModelHistorysMapper historysMapper;

	@Override
	public void notify(DelegateTask delegateTask) {
		// 获取用户任务节点ID
		String nodeId = delegateTask.getTaskDefinitionKey();
		// assignment时间早于create触发，此时还没有创建成功task
		if ("create".equals(delegateTask.getEventName())) {
			// 当任务被指派时，判断任务指派人是不是属于系统自动办理
			String assignee = delegateTask.getAssignee();
			if (WflowGlobalVarDef.WFLOW_TASK_AGRRE.equals(assignee)
					|| WflowGlobalVarDef.WFLOW_TASK_REFUSE.equals(assignee)) {
				boolean result = WflowGlobalVarDef.WFLOW_TASK_AGRRE.equals(assignee);
				Map<String, Object> var = new HashMap<>();
				var.put("approve_" + delegateTask.getId(),
						result ? ProcessHandlerParamsVo.Action.agree : ProcessHandlerParamsVo.Action.refuse);
				taskService.complete(delegateTask.getId(), var);
				log.info("无审批人任务节点[{}]，交付系统控制[审批结果 {}]", nodeId, result);
			}
			else {
				processChangeNotify(delegateTask, false);
				log.info("实例[{}]的节点[{}]任务被指派给[{}]处理", delegateTask.getProcessInstanceId(),
						delegateTask.getTaskDefinitionKey(), assignee);
			}
		}
		else if ("complete".equals(delegateTask.getEventName())) {
			// 当任务完成时，判断是不是驳回，驳回就执行驳回操作
			ProcessHandlerParamsVo.Action action = delegateTask.getVariable("approve_" + delegateTask.getId(),
					ProcessHandlerParamsVo.Action.class);
			// 获取当前执行实例
			if (ProcessHandlerParamsVo.Action.refuse.equals(action)) {
				List<Execution> executions = runtimeService.createExecutionQuery()
					.parentId(delegateTask.getProcessInstanceId())
					.onlyChildExecutions()
					.list();
				Map nodeProps = delegateTask.getVariable(WflowGlobalVarDef.WFLOW_NODE_PROPS, Map.class);
				ApprovalProps props = (ApprovalProps) nodeProps.get(nodeId);
				String target = "TO_NODE".equals(props.getRefuse().getType()) ? props.getRefuse().getTarget()
						: "refuse-end";
				// 强制流程指向驳回/其他
				ChangeActivityStateBuilder builder = runtimeService.createChangeActivityStateBuilder()
					.processInstanceId(delegateTask.getProcessInstanceId());
				if (executions.size() > 1) {
					// 多实例
					builder
						.moveExecutionsToSingleActivityId(
								executions.stream().map(Execution::getId).collect(Collectors.toList()), target)
						.changeState();
				}
				else {
					builder.moveActivityIdTo(delegateTask.getTaskDefinitionKey(), target).changeState();
				}
				if ("TO_END".equals(props.getRefuse().getType())) {
					processChangeNotify(delegateTask, true);
				}
			}
			log.info("任务[{} - {}]由[{}]完成", delegateTask.getTaskDefinitionKey(), delegateTask.getName(),
					delegateTask.getAssignee());
		}
	}

	@Override
	public void notify(DelegateExecution execution) {
		log.info("执行监听触发[活动:{}]", execution.getCurrentActivityId());
	}

	private void processChangeNotify(DelegateTask delegateTask, boolean isRefuse) {
		String instanceId = delegateTask.getProcessInstanceId();
		String dfId = delegateTask.getProcessDefinitionId();
		String startUser = String.valueOf(delegateTask.getVariable(WflowGlobalVarDef.INITIATOR));
		String assignee = delegateTask.getAssignee();
		ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
			.processInstanceId(instanceId)
			.singleResult();
		String defName = "??";
		if (Objects.nonNull(processInstance)) {
			defName = processInstance.getProcessDefinitionName();
		}
		else {
			WflowModelHistorys modelHistory = historysMapper
				.selectOne(new LambdaQueryWrapper<WflowModelHistorys>().select(WflowModelHistorys::getFormName)
					.eq(WflowModelHistorys::getProcessDefId, dfId));
			if (Objects.nonNull(modelHistory)) {
				defName = modelHistory.getFormName();
			}
		}
		OrgUser orgUser = userService.getUserMapByIds(CollectionUtil.newArrayList(startUser)).get(startUser);
		notifyService.notify(NotifyDto.builder()
			.title(isRefuse ? "您提交的审批被驳回" : "您有新的待办任务")
			.processDefId(dfId)
			.instanceId(instanceId)
			.nodeId(delegateTask.getTaskDefinitionKey())
			.target(isRefuse ? startUser : assignee)
			.content(isRefuse ? StrUtil.builder("您提交的【", defName, "】已被驳回").toString()
					: StrUtil.builder(orgUser.getName(), " 提交的【", defName, "】需要您审批，请即时处理").toString())
			.type(isRefuse ? NotifyDto.TypeEnum.ERROR : NotifyDto.TypeEnum.WARNING)
			.build());
	}

}
